home *** CD-ROM | disk | FTP | other *** search
Wrap
/* Copyright (c) 1995-1999 NEC USA, Inc. All rights reserved. */ /* */ /* The redistribution, use and modification in source or binary forms of */ /* this software is subject to the conditions set forth in the copyright */ /* document ("Copyright") included with this distribution. */ /* * $Id: udp.c,v 1.80.2.1.2.8 1999/02/03 22:35:52 steve Exp $ */ /* This file has all the main functions for handling udp connections. In */ /* particular it only one external function which is the main udp function, */ /* HandleUdpConnection(). */ #include "socks5p.h" #include "threads.h" #include "daemon.h" #include "protocol.h" #include "validate.h" #include "udputil.h" #include "msgids.h" #include "info.h" #include "msg.h" #include "s2s.h" #include "udp.h" #include "log.h" #ifndef UDPTIMEOUT #define UDPTIMEOUT 15*60 #endif #define CODEABLE(x) ((x) && (x)->auth.encode) #define CODEBUFF(a, b, c, d) ((a)->auth.encode(b, c, d, (a)->auth.context)) #define NEXTADDR(x) (((x)->nextVersion)?&((x)->sckAddr) :&((x)->dstAddr)) #define NEXTNAME(x) (((x)->nextVersion)? ((x)->sckName): ((x)->dstName)) /* Close all the file descriptor, clean up the caches, log the exit error, */ /* and quit... */ static void UdpCleanup(S5LinkInfo *pri, UdpInfo *u) { S5IOHandle i; void *tmp; if (!u) return; for (; u->scache ; u->scache = (struct scache *)tmp) { S5BufCleanContext(&u->scache->cinfo); RemoveIdentEntry(u->scache->idtentry); tmp = (void *)u->scache->next; free(u->scache); } S5BufCleanContext(&u->iio); for (i = 0; i < u->maxfd; i++) { if (FD_ISSET(i, &u->myfds)) CLOSESOCKET(i); } if (u->relay != S5InvalidIOHandle) CLOSESOCKET(u->relay); for (; u->acache ; u->acache = (struct acache *)tmp) { tmp = (void *)u->acache->next; free(u->acache); } for (; u->rcache ; u->rcache = (struct aroute *)tmp) { tmp = (void *)u->rcache->next; free(u->rcache); } for (; u->hcache; u->hcache = (struct hinfo *)tmp) { tmp = (void *)u->hcache->next; free(u->hcache); } tmp = (void *)u->sdring->next; u->sdring->next = NULL; u->sdring = (UdpSdRing *)tmp; for (; u->sdring; u->sdring = (UdpSdRing *)tmp) { tmp = (void *)u->sdring->next; free(u->sdring); } S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_UDP_END, "UDP Proxy Termination: (%s:%d) for user %s; %d bytes out %d bytes in", pri->srcName, ntohs(lsAddr2Port(&pri->srcAddr)), pri->srcUser, pri->outbc, pri->inbc); free(u); u = NULL; } /* Process udp use_client_port sub-command. */ static void UdpUseClientPort(S5LinkInfo *pri, UdpInfo *u, u_char *err) { /* do we need this ???? */ S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Command: Doing USECLIENTPORT command"); if (!lsAddrAddrComp(&pri->dstAddr, &pri->srcAddr) || pri->dstAddr.sin.sin_addr.s_addr == INADDR_ANY || pri->dstAddr.sin.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { pri->clientPort = lsAddr2Port(&pri->dstAddr); *err = SOCKS5_NOERR; } } /* Process udp bind sub-command. */ static void UdpBind(S5LinkInfo *pri, UdpInfo *u, u_char *err) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Command: Doing BIND command"); if (ResolveNames(pri) < 0) return; if (!lsAddrIsNull(&pri->dstAddr)) { *err = SOCKS5_BADADDR; return; } if (CheckIfCached(u, pri, 1) == 0) { if (u->curs != NULL) { if (S5IOCheck(u->curs->cinfo.fd) < 0) return; /* should it re-establish??? */ if (u->curs->reserved != S5UDP_USECTRL) { lsAddrCopy(&pri->intAddr, &u->curr->raddr, sizeof(S5NetAddr)); *err = SOCKS5_NOERR; return; } else { if (u->cura->bounded) lsAddrCopy(&pri->intAddr, &u->cura->baddr, sizeof(S5NetAddr)); else if (S5SExchgUdpCmd(u->curs->cinfo.fd, &u->curs->cinfo, pri, SOCKS5_VERSION, S5UDP_BIND, err) < 0) return; } } else lsAddrCopy(&pri->intAddr, &u->curr->raddr, sizeof(S5NetAddr)); } else { if (CheckIfAllowed(u, pri) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "UDP Command: Bind failed: permission denied"); *err = SOCKS5_AUTHORIZE; return; } if (pri->nextVersion == SOCKS5_VERSION && FindProxyEntry(u, pri, &pri->sckAddr, 1) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Command: Couldn't connect to proxy: %s:%d", ADDRANDPORT(&pri->sckAddr)); return; } else if (pri->nextVersion == SOCKS5_VERSION) { if (!(pri->nextReserved & S5UDP_USECTRL)) { /* S5NetAddr na; char msg = '\0'; lsAddrCopy(&na, &pri->dstAddr, lsAddrSize(&pri->dstAddr)); lsAddrSetPort(&na, 9); if (lsUdpProtoSend(pcon->fd, pri, &msg, 1, 0, &na.sa, lsAddrSize(&na)) < 0) return; lsAddrCopy(&pri->intAddr, &u->curr->raddr, sizeof(S5NetAddr)); *err = SOCKS5_NOERR; */ return; } else if (S5SExchgUdpCmd(u->curs->cinfo.fd, &u->curs->cinfo, pri, SOCKS5_VERSION, S5UDP_BIND, err) < 0) return; } else if (pri->nextVersion != SOCKS5_VERSION) { if (FindOutSocket(u, pri, &pri->dstAddr, pri->dstName) == S5InvalidIOHandle) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Command: Couldn't make out socket to destination: %s:%d", ADDRANDPORT(&pri->dstAddr)); return; } } } u->cura->bounded = 1; lsAddrCopy(&u->cura->baddr, &pri->intAddr, sizeof(S5NetAddr)); *err = SOCKS5_NOERR; } /* Process udp getsockname sub-command. */ static void UdpGetsockname(S5LinkInfo *pri, UdpInfo *u, u_char *err) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Command: Doing GETSOCKNAME command"); if (ResolveNames(pri) < 0) return; if (!lsAddrIsNull(&pri->dstAddr)) { *err = SOCKS5_BADADDR; return; } if (CheckIfCached(u, pri, 1) < 0) return; if (u->curs != NULL) { if (u->curs->reserved != S5UDP_USECTRL) return; if (S5IOCheck(u->curs->cinfo.fd) < 0) return; if (u->cura->bounded) lsAddrCopy(&pri->intAddr, &u->cura->baddr, sizeof(S5NetAddr)); else if (S5SExchgUdpCmd(u->curs->cinfo.fd, &u->curs->cinfo, pri, SOCKS5_VERSION, S5UDP_GETSOCKNAME, err) < 0) return; } else lsAddrCopy(&pri->intAddr, &u->curr->raddr, sizeof(S5NetAddr)); u->cura->bounded = 1; lsAddrCopy(&u->cura->baddr, &pri->intAddr, sizeof(S5NetAddr)); *err = SOCKS5_NOERR; } /* Process udp sub-commands received on the tcp control channel. */ /* Current implementation supports three sub-commands. People should be */ /* able to add new sub-commands */ static int HandleCommand(S5LinkInfo *pri, UdpInfo *u) { u_char cmd = 0, res = 0, s5err = SOCKS5_BADCMND; memset((char *)&pri->intAddr, 0, sizeof(S5NetAddr)); pri->intAddr.sa.sa_family = AF_INET; if (lsReadRequest(u->iio.fd, &u->iio, &pri->dstAddr, &pri->peerVersion, &cmd, &res) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Command: Read request command failed"); return -1; } S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Command: Read command (%d) request (%s:%d)", (int)cmd, ADDRANDPORT(&pri->dstAddr)); switch (cmd) { case S5UDP_USECLIENTPORT: UdpUseClientPort(pri, u, &s5err); break; case S5UDP_BIND: UdpBind(pri, u, &s5err); break; case S5UDP_GETSOCKNAME: UdpGetsockname(pri, u, &s5err); break; default: S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Command: Unknown command"); break; } return lsSendResponse(u->iio.fd, &u->iio, &pri->intAddr, pri->peerVersion, s5err, 0, NULL); } /* Proxy a request for the client. This basically involves checking to see */ /* that the information is correct, then checking to see if it is allowed to */ /* send to the destination (in FindOutDestination) as well as finding the */ /* intermediate destination...If the destination turns out to be directly */ /* reachable, then we may reassemble a fragment and send that instead. */ /* */ /* Arguments: sin -- the address of the person who sent the message to us */ static int RecvFromClient(S5Packet *packet, S5LinkInfo *pri, UdpInfo *u, S5NetAddr *sender) { S5Packet buf[2]; /* Make sure the client really sent this message. If not, assume it is */ /* a forgery. */ if (lsAddrComp(&pri->srcAddr, sender)) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "UDP Client Receive: Received message from non-client (%s:%d) on client socket", ADDRANDPORT(sender)); return -1; } /* Decode the message and copy the decode message into u->obuf. */ if (CODEABLE(&u->iio)) { buf[0].data = u->obuf; buf[0].len = u->obuflen; buf[0].off = u->obuflen; buf[1].data = NULL; buf[1].len = 0; buf[1].off = 0; if (CODEBUFF(&u->iio, &buf[0], &buf[1], S5_DECODE) < 0 || buf[1].len > UDP_MAX_PAYLOAD) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "UDP Client Receive: Error decoding message"); return -1; } else { memcpy(u->obuf, buf[1].data, buf[1].len); u->obuflen = buf[1].len; free(buf[1].data); } } /* A real message would have to have a length greater than the header */ /* size. Drop the message if it does not. */ if (u->obuflen <= MINHDRSIZE) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Client Receive: Received invalid message from client: too short"); return -1; } /* Extract the destination address and it's name. */ if (lsGetProtoAddr(SOCKS5_VERSION, u->obuf, &pri->dstAddr) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Client Receive: Received invalid message from client: invalid address"); return -1; } if (ResolveNames(pri) < 0) { return -1; } /* Make sure we've either talked to this destination before, or we are */ /* allowed to talk to it... */ if (CheckIfCached(u, pri, 1) < 0 && CheckIfAllowed(u, pri) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Client Receive: send failed: permission denied"); return -1; } packet->data = u->obuf + HDRSIZE(u->obuf); packet->off = u->obuflen - HDRSIZE(u->obuf); packet->len = UDP_MAX_PAYLOAD; S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Client Receive: Received valid message of length %d", u->obuflen-HDRSIZE(u->obuf)); return u->obuflen - HDRSIZE(u->obuf); } /* Proxy a request back from a server. This basically involves checking to */ /* see if this is from a server we've talked to (FindCachedSocks) in which */ /* case we forward it on... If not, it was from the application server. */ /* To handle this case, we first check that this server is allowed (cache?) */ /* then, if it is, package it up (possibly fragmenting it) and ship it back */ /* to the client. */ /* */ /* Arguments: sin -- the address of the person who sent the message to us */ static int RecvFromServer(S5Packet *packet, S5LinkInfo *pri, UdpInfo *u, S5NetAddr *sender) { S5Packet buf[2]; /* If we don't find a proxy entry, zero out the appropriate structures */ /* so that when we look at them later, we don't do something wrong. If */ /* we did find one, go ahead and look up its name for logging... */ pri->dstAddr = *sender; if (FindProxyEntry(u, pri, &pri->dstAddr, 0) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Server Receive: Received message from dead server"); return -1; } /* If we have a decode function for the server, go ahead and decode the */ /* message and move it into the appropriate place */ if (CODEABLE(u->oiop)) { buf[0].data = u->obuf; buf[0].len = u->obuflen; buf[0].off = u->obuflen; buf[1].data = NULL; buf[1].len = 0; buf[1].off = 0; if (CODEBUFF(u->oiop, &buf[0], &buf[1], S5_DECODE) < 0 || buf[1].len > UDP_MAX_PAYLOAD) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Server Receive: Error decoding message from server"); return -1; } else { memcpy(u->obuf, buf[1].data, buf[1].len); u->obuflen = buf[1].len; free(buf[1].data); } } /* If FindProxyEntry told us this was from another socks server, strip */ /* off the header that it put on the message... */ if (pri->nextVersion == SOCKS5_VERSION) { if (lsGetProtoAddr(SOCKS5_VERSION, u->obuf, &pri->dstAddr) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Server Receive: Received invalid message from server: invalid address"); return -1; } u->obuflen -= HDRSIZE(u->obuf); u->obuf += HDRSIZE(u->obuf); } GetName(pri->dstName, &pri->dstAddr); /* Make sure we've talked to the sender before. If not, we will ignore */ /* this reply, assuming that this is a forgery. */ if (CheckIfCached(u, pri, 1) < 0 && CheckIfAllowed(u, pri) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Server Receive: recv failed: permission denied"); return -1; } packet->data = u->obuf; packet->len = UDP_MAX_PAYLOAD; packet->off = u->obuflen; S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "UDP Server Receive: Received valid message of length %d", u->obuflen); return u->obuflen; } int UdpRecvPkt(S5Packet *packet, S5LinkInfo *pri, UdpInfo *u, int *dir) { S5IOHandle maxfd; fd_set fds; UdpSdRing *sr; int rval; for (;;) { struct timeval inact = { UDPTIMEOUT, 0 }; if (*dir & S5_DIRECTION_IN) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "UDP Receive: Selecting on outer sockets..."); maxfd = u->maxfd; fds = u->myfds; } else { maxfd = 0; FD_ZERO(&fds); } if (*dir & S5_DIRECTION_OUT) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "UDP Receive: Selecting on inner socket..."); FD_SET(u->relay, &fds); maxfd = MAX(maxfd, u->relay); } FD_SET(u->iio.fd, &fds); maxfd = MAX(maxfd, u->iio.fd); S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "UDP Receive: Selecting..."); switch (select(maxfd+1, &fds, NULL, NULL, &inact)) { case 0: S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Receive: Inactivity timeout expired"); rval = -1; goto end; case -1: if (ISSOCKETERROR(EINTR)) continue; S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Receive: select failed: %m"); rval = -1; goto end; } if (FD_ISSET(u->iio.fd, &fds)) { if (S5IOCheck(u->iio.fd) < 0) rval = 0; else if ((pri->peerReserved & S5UDP_USECTRL) && !HandleCommand(pri, u)) continue; else { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Receive: client closed connection"); rval = -1; } goto end; } if (u->sdring) u->sdring = u->sdring->next; for (sr = u->sdring;sr;sr = (u->sdring==sr->next)?NULL:sr->next) { int fromlen = sizeof(S5NetAddr); S5NetAddr sender; if (!FD_ISSET(sr->sd, &fds)) continue; u->obuf = u->mbuf + MAXHDRSIZE; u->obuflen = sizeof(u->mbuf) - MAXHDRSIZE; while ((u->obuflen = recvfrom(sr->sd, u->obuf, u->obuflen, 0, (ss *)&sender, &fromlen)) < 0 && ISSOCKETERROR(EINTR)); if (u->obuflen < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "UDP Receive: real recvfrom failed: %m"); rval = -1; goto end; } S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Receive: received a message from %s:%d", ADDRANDPORT(&sender)); if (sr->sd == u->relay) { if ((rval = RecvFromClient(packet, pri, u, &sender)) <= 0) continue; *dir = S5_DIRECTION_OUT; } else { if ((rval = RecvFromServer(packet, pri, u, &sender)) <= 0) continue; *dir = S5_DIRECTION_IN; } goto end; } } end: if (rval <= 0) { packet->data = NULL; packet->off = 0; packet->len = 0; } return rval; } int UdpSendPkt(S5Packet *packet, S5LinkInfo *pri, UdpInfo *u, int *dir) { S5Packet buf[2]; S5NetAddr *dst; S5IOInfo *info; S5IOHandle fd; int alen; if (packet->data < u->mbuf + MAXHDRSIZE || packet->data > u->mbuf + MAXHDRSIZE + UDP_MAX_PAYLOAD ) { char *tmp; if ((tmp = (char *)malloc(packet->off)) == NULL) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "UDP send: Malloc failed."); u->obuflen = -1; goto end; } memcpy(tmp, packet->data, packet->off); u->obuf = u->mbuf + MAXHDRSIZE; u->obuflen = packet->off; memcpy(u->obuf, tmp, u->obuflen); free(tmp); } else { u->obuf = packet->data; u->obuflen = packet->off; } if (*dir == S5_DIRECTION_IN) { dst = &pri->srcAddr; fd = u->relay; info = &u->iio; } else { /* If we'll be using a proxy and we haven't talked to it yet, */ /* initialize the connection and add it it list of know proxies... */ if (pri->nextVersion == SOCKS5_VERSION && FindProxyEntry(u, pri, &pri->sckAddr, 1) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP send: Couldn't connect to %s:%d", ADDRANDPORT(&pri->sckAddr)); u->obuflen = -1; goto end; } /* Find out how we should go out, update the byte count, and dump */ /* the packet if need be. */ fd = FindOutSocket(u, pri, NEXTADDR(pri), NEXTNAME(pri)); dst = NEXTADDR(pri); info = u->oiop; } S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Send: Sending to %s:%d", ADDRANDPORT(dst)); if (*dir == S5_DIRECTION_IN || pri->nextVersion == SOCKS5_VERSION) { if ((alen = lsGetProtoAddrLenFromAddr(SOCKS5_VERSION, &pri->dstAddr)) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Send: Error filling in address in packet header"); u->obuflen = -1; goto end; } u->obuf -= alen; memset(u->obuf, 0, 3); lsSetProtoAddr(SOCKS5_VERSION, u->obuf, &pri->dstAddr); u->obuflen += HDRSIZE(u->obuf); } /* Encode the packet if necessary... This includes changing obuf to */ /* point to the buffer that the encoding creates. We'll free that */ /* buffer later if need be. */ if (CODEABLE(info)) { buf[0].data = u->obuf; buf[0].len = u->obuflen; buf[0].off = 0; buf[1].data = NULL; buf[1].len = 0; buf[1].off = 0; if (CODEBUFF(info, &buf[0], &buf[1], S5_ENCODE) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Send: Error encoding message for client"); u->obuflen = -1; goto end; } else { u->obuf = buf[1].data; u->obuflen = buf[1].len; } } S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Send: Sending a message of length %d", u->obuflen); /* Send the message and log the fact that we have. */ if (sendto(fd, u->obuf, u->obuflen, 0, &dst->sa, sizeof(ssi)) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Send: Sendto failed: %m"); } else if (*dir == S5_DIRECTION_OUT) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Send: Client Sent Message to %s:%d", ADDRANDPORT(dst)); } else { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Send: Client Recveived Message from %s:%d", ADDRANDPORT(&pri->dstAddr)); } /* Free any space we had to allocate because of the encoding */ if (CODEABLE(info)) { if (buf[1].data) free(buf[1].data); } end: packet->data = NULL; packet->off = 0; packet->len = 0; return u->obuflen; } int UdpSetup(S5IOInfo *ioinfo, S5LinkInfo *pri, S5CommandInfo *cmdinfo) { int len = sizeof(S5NetAddr), rval = EXIT_ERR; S5NetAddr route; u_char s5err = SOCKS5_FAIL; UdpInfo *u = NULL; /* The destination is really the port we'll be receiving request from */ /* it is allowed to be 0, but we take that to mean we'll be recv'ing it */ /* from the same place the tcp connection came from, different port */ if (lsAddrAddrComp(&pri->dstAddr, &pri->srcAddr) != 0) { if (pri->dstAddr.sin.sin_addr.s_addr != INADDR_ANY && pri->dstAddr.sin.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { s5err = SOCKS5_BADADDR; goto cleanup; } } /* Allocate space for the udp specific options we'll be using... */ if (!(cmdinfo->option = (void *)(u = (UdpInfo *)calloc(1, sizeof(UdpInfo))))) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "UDP Setup: Malloc() failed"); goto cleanup; } u->sdring = NULL; u->iio = *ioinfo; memset(&u->myfds, 0, sizeof(fd_set)); S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_UDP_START, "UDP Proxy Request: (%s:%d) for user %s", pri->srcName, ntohs(lsAddr2Port(&pri->srcAddr)), pri->srcUser); /* if the destination port is 0, we will assume the same port as tcp's */ if (lsAddr2Port(&pri->dstAddr) != (u_short)0) lsAddrSetPort(&pri->srcAddr, lsAddr2Port(&pri->dstAddr)); /* We set the destination address same as the source for Authorize */ /* function to distinguish the UDP request and UDP messages ... */ lsAddrCopy(&pri->dstAddr, &pri->srcAddr, lsAddrSize(&pri->srcAddr)); if (Authorize(pri, 0) != AUTH_OK) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "UDP Setup: Setup failed: permission denied"); s5err = SOCKS5_AUTHORIZE; rval = EXIT_AUTH; goto cleanup; } lsAddrCopy(&route, &pri->bndAddr, lsAddrSize(&pri->bndAddr)); lsAddrSetPort(&route, (u_short)0); if ((u->relay = MakeOutSocket(u, &route, (u_short)0)) == S5InvalidIOHandle) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "UDP Setup: Couldn't make main udp socket: %m"); goto cleanup; } if (getsockname(u->relay, (ss *)&route.sa, &len) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "UDP Setup: Getsockname failed on main udp socket: %m"); goto cleanup; } lsAddrSetPort(&pri->bndAddr, lsAddr2Port(&route)); if (lsSendResponse(u->iio.fd, &u->iio, &pri->bndAddr, pri->peerVersion, SOCKS5_RESULT, (pri->peerReserved & S5UDP_USECTRL)?S5UDP_USECTRL:0, NULL) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "UDP Setup: couldn't send response"); rval = EXIT_NETERR; goto cleanup; } S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_UDP_ESTAB, "UDP Proxy Established: (%s:%d) for user %s", pri->srcName, ntohs(lsAddr2Port(&pri->srcAddr)), pri->srcUser); cmdinfo->recvpkt = (int (*)(S5Packet *, S5LinkInfo *, void *, int *))UdpRecvPkt; cmdinfo->sendpkt = (int (*)(S5Packet *, S5LinkInfo *, void *, int *))UdpSendPkt; cmdinfo->clean = (int (*)(S5LinkInfo *, void *))UdpCleanup; return EXIT_OK; cleanup: if (rval != EXIT_NETERR) lsSendResponse(ioinfo->fd, ioinfo, &pri->bndAddr, pri->peerVersion, s5err, 0, NULL); if (u != NULL) UdpCleanup(pri, u); else { S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_UDP_END, "UDP Proxy Termination: (%s:%d) for user %s; %d bytes out %d bytes in", pri->srcName, ntohs(lsAddr2Port(&pri->srcAddr)), pri->srcUser, pri->outbc, pri->inbc); S5BufCleanContext(ioinfo); } /* Prevent any further problems from being seg faults. */ cmdinfo->option = NULL; if (rval == EXIT_OK) rval = EXIT_ERR; return rval; }